package com.ruoyi.project.system.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 对象到Map解构工具类
 * 
 * @author ruoyi
 * @date 2025-01-27
 */
public class ObjectToMapUtils {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 方法1：使用反射将对象属性解构到Map
     * 
     * @param obj 要解构的对象
     * @return 包含对象所有属性的Map
     */
    public static Map<String, Object> objectToMapByReflection(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }

        try {
            Class<?> clazz = obj.getClass();
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(obj);
                map.put(field.getName(), value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return map;
    }

    /**
     * 方法2：使用Jackson将对象转换为Map
     * 
     * @param obj 要解构的对象
     * @return 包含对象所有属性的Map
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> objectToMapByJackson(Object obj) {
        if (obj == null) {
            return new HashMap<>();
        }

        try {
            return objectMapper.convertValue(obj, Map.class);
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap<>();
        }
    }

    /**
     * 方法3：手动指定要解构的属性
     * 
     * @param obj        要解构的对象
     * @param fieldNames 要解构的属性名数组
     * @return 包含指定属性的Map
     */
    public static Map<String, Object> objectToMapByFields(Object obj, String... fieldNames) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null || fieldNames == null) {
            return map;
        }

        try {
            Class<?> clazz = obj.getClass();
            for (String fieldName : fieldNames) {
                try {
                    Field field = clazz.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    Object value = field.get(obj);
                    map.put(fieldName, value);
                } catch (NoSuchFieldException e) {
                    // 字段不存在，跳过
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return map;
    }

    /**
     * 方法4：将对象解构到Map中，同时添加额外信息
     * 
     * @param obj            要解构的对象
     * @param additionalInfo 额外的信息Map
     * @return 包含对象属性和额外信息的Map
     */
    public static Map<String, Object> objectToMapWithInfo(Object obj, Map<String, Object> additionalInfo) {
        Map<String, Object> result = objectToMapByReflection(obj);
        if (additionalInfo != null) {
            result.putAll(additionalInfo);
        }
        return result;
    }

    /**
     * 方法5：将对象解构到Map中，使用自定义的键名映射
     * 
     * @param obj              要解构的对象
     * @param fieldNameMapping 字段名映射，key为原字段名，value为新字段名
     * @return 包含重命名属性的Map
     */
    public static Map<String, Object> objectToMapWithMapping(Object obj, Map<String, String> fieldNameMapping) {
        Map<String, Object> originalMap = objectToMapByReflection(obj);
        Map<String, Object> result = new HashMap<>();

        for (Map.Entry<String, Object> entry : originalMap.entrySet()) {
            String originalKey = entry.getKey();
            String newKey = fieldNameMapping.getOrDefault(originalKey, originalKey);
            result.put(newKey, entry.getValue());
        }

        return result;
    }

    /**
     * 方法6：将对象解构到Map中，只包含非null的属性
     * 
     * @param obj 要解构的对象
     * @return 包含非null属性的Map
     */
    public static Map<String, Object> objectToMapNonNull(Object obj) {
        Map<String, Object> allFields = objectToMapByReflection(obj);
        Map<String, Object> result = new HashMap<>();

        for (Map.Entry<String, Object> entry : allFields.entrySet()) {
            if (entry.getValue() != null) {
                result.put(entry.getKey(), entry.getValue());
            }
        }

        return result;
    }
}